package com.king.components.pagination;

import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.stereotype.Component;

import com.king.util.page.PageCore;

import atlantafx.base.theme.Styles;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Spinner;
import javafx.scene.layout.HBox;
import lombok.extern.slf4j.Slf4j;
import net.rgielen.fxweaver.core.FxmlView;

/**
 * 分页
 *
 * @author king
 * @date 2025年6月24日-13:15:57
 */
@Slf4j
@FxmlView
@Component
public class KingPagination {

	@FXML
	private Spinner<Integer> toPageSpinner;

	@FXML
	private MenuButton pageSizeBtn;

	@FXML
	private HBox pageNums;

	@FXML
	private Label msg;

	private String msgFmt = "共%s条 | %s页";

	private int totalSize;

	private IntegerProperty currentPage;

	private IntegerProperty pageSize;

	private int totalPage;

	private int maxBtnNum = 6;

	private int[] btnRange = { 0, 0 };

	private String[] activeCls = { "k-active", Styles.ACCENT };

	private Call call;

	private PageCore search;

	@FXML
	private void initialize() {
		pageSize = new SimpleIntegerProperty(12);
		currentPage = new SimpleIntegerProperty(1);
		toPageSpinner.valueProperty().addListener((_, _, n) -> {
			if (n > totalPage) {
				toPageSpinner.getValueFactory().setValue(totalPage);
				// 如果超套当前最大页数，那么直接return，后续逻辑都不要执行了
				return;
			}
			if (this.currentPage.getValue().equals(n)) {
				// 就是当前页就不用执行了
				return;
			}
			changePage(n);
			if (call != null) {
				call.done();
			}
		});
	}

	/**
	 * 设置数据量
	 * 
	 * @param count
	 * @return
	 * @author king
	 * @date 2025年6月25日-13:48:24
	 */
	public KingPagination setTotalSize(int count) {
		if (count <= 0) {
			return this;
		}
		totalPage = count / pageSize.getValue();
		if (count % pageSize.getValue() != 0) {
			totalPage++;
		}
		msg.setText(String.format(msgFmt, count, totalPage));
		if (this.totalPage != count) {
			this.totalSize = count;
			donePageNumBtns(this.currentPage.getValue());
		}
		return this;
	}

	/**
	 * 开始生成页码按钮，并跳转到第一页，设置pageSize，currentPage值变化的回调
	 * 
	 * @param call
	 * @param auto 是否立即运行加载函数，传入了之后，会立即调用auto方法的done方法
	 * @author king
	 * @date 2025年6月25日-14:37:53
	 */
	public void go(PageCore search, Call call) {
		this.search = search;
		this.call = call;
		this.currentPage.setValue(1);
		if (this.search != null) {
			this.search.setCurrentPage(this.currentPage.getValue());
			this.search.setPageSize(this.pageSize.getValue());
		}
		if (call != null) {
			call.done();
		}
		donePageNumBtns(this.currentPage.getValue());
	}

	/**
	 * 重置页码按钮
	 *
	 * @param start
	 * @author king
	 * @date 2025年6月25日-11:13:30
	 */
	private void donePageNumBtns(int start) {
		// 保持当前页的前面有3个按钮
		start = Math.max(1, start - 3);
		if (totalPage <= maxBtnNum) {
			btnRange[0] = start = 1;
			btnRange[1] = totalPage;
		} else {
			start = Math.min(start, totalPage - maxBtnNum + 1);
			btnRange[0] = start;
			btnRange[1] = Math.min(start + maxBtnNum - 1, totalPage);
		}
		Button btn;

		// 处理当前按钮数量
		int btns = pageNums.getChildren().size();
		/*
		 * 当按钮数量大于数值区间，那么将多余的移除，反之则添加 如，当前区间是[1,6]，btns是0，那么应该要添加6-1+1
		 */
		int redundant = (btnRange[1] - btnRange[0]) + 1 - btns;
		if (redundant < 0) {
			pageNums.getChildren().remove(0, Math.abs(redundant));
		} else {
			for (; redundant > 0; redundant--) {
				btn = new Button();
				pageNums.getChildren().add(btn);
				btn.getStyleClass().add(Styles.FLAT);
				btn.setOnAction(this::onAction);
			}
		}
		int i = 0;
		for (; start <= btnRange[1]; start++) {
			btn = (Button) pageNums.getChildren().get(i);
			btn.setText(String.valueOf(start));
			i++;
		}
	}

	/**
	 * 点击数字按钮
	 *
	 * @param e
	 * @author king
	 * @date 2025年6月25日-09:51:43
	 */
	private void onAction(ActionEvent e) {
		Button b = (Button) e.getTarget();
		Integer num = Integer.valueOf(b.getText());
		toPageSpinner.getValueFactory().setValue(num);
	}

	public void to(int num) {
		toPageSpinner.getValueFactory().setValue(num);
	}

	@FXML
	private void prev() {
		if (totalSize == 0 || totalPage == 0) {
			return;
		}
		if (this.currentPage.getValue() == 1) {
			return;
		}
		toPageSpinner.getValueFactory().setValue(this.currentPage.getValue() - 1);
	}

	@FXML
	private void next() {
		if (totalSize == 0 || totalPage == 0) {
			return;
		}
		if (this.currentPage.getValue() == totalPage) {
			return;
		}
		toPageSpinner.getValueFactory().setValue(this.currentPage.getValue() + 1);
	}

	/**
	 * 切换页码
	 *
	 * @param num
	 * @author king
	 * @date 2025年6月25日-09:53:32
	 */
	private void changePage(Integer num) {
		if (this.search != null) {
			this.search.setCurrentPage(num);
		}
		ObservableList<Node> nums = pageNums.getChildren();
		if (totalSize == 0 || totalPage == 0) {
			return;
		}
		if (this.currentPage.getValue().equals(num)) {
			return;
		}

		/*
		 * 如果当前有20页，最大显示按钮数是6，那么当按钮按下在6以下的任何一个按钮，都不会触发重新置换按钮的方法。
		 * 当然，如果要去的页面如果是在14及以上，页不会重新绘制。但是这有个问题，因为这样的话，相当于如果我直接从第8页来到第一页，
		 * 那么就会出现不能重写置换按钮的情况
		 */
		if (num.equals(btnRange[0])) {
			donePageNumBtns(num - maxBtnNum);
		} else {
			donePageNumBtns(num);
		}

		this.currentPage.setValue(num);

		Button btn;
		for (Node n : nums) {
			btn = (Button) n;
			if (btn.getText().equals(String.valueOf(num))) {
				btn.getStyleClass().addAll(activeCls);
			} else {
				if (btn.getStyleClass().containsAll(Arrays.asList(activeCls))) {
					btn.getStyleClass().removeAll(activeCls);
				}
			}
		}
	}

	@FXML
	private void onChangePageSize(ActionEvent e) {
		try {
			int pageSize;
			pageSize = parsePageSize(((MenuItem) e.getTarget()).getText());

			if (this.pageSize.getValue().equals(pageSize)) {
				return;
			}

			this.pageSize.setValue(pageSize);
			pageSizeBtn.setText(pageSize + " / 页");
			setTotalSize(totalSize);
			if (call != null) {
				if (this.search != null) {
					this.search.setPageSize(pageSize);
				}
				call.done();
			}
			toPageSpinner.getValueFactory().setValue(1);
		} catch (Exception e1) {
			e1.printStackTrace();
		}
	}

	/**
	 * 解析每页数量
	 *
	 * @param text
	 * @return
	 * @throws Exception
	 * @author king
	 * @date 2025年6月24日-15:20:23
	 */
	private Integer parsePageSize(String text) throws Exception {
		Pattern p = Pattern.compile("\\d+");
		Matcher m = p.matcher(text);
		if (m.find()) {
			return Integer.valueOf(m.group());
		}
		return 12;
	}

	public KingPagination pageSize(int pageSize) {
		this.pageSize.setValue(pageSize);
		return this;
	}

	public interface Call {
		public void done();
	}

	public interface AutoLoad {
		public void done();
	}

}
